{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "57b0ae99-4212-4192-af9a-6582bb87c08a",
   "metadata": {},
   "source": [
    "Chapter 03\n",
    "\n",
    "# Python自定义函数计算矩阵乘法，行向量线性组合视角\n",
    "《线性代数》 | 鸢尾花书：数学不难"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5651011d-eaeb-458e-956c-08bb89e7a7a3",
   "metadata": {},
   "source": [
    "这段代码从数学角度重新阐释了**矩阵乘法的行向量线性组合视角**，本质上与传统的矩阵乘法是一致的，但提供了另一种对“线性运算”的理解方式。代码分为两个主要部分：一个用于实现**行向量的线性组合**，另一个用于基于该组合思想完成矩阵乘法 $AB$。\n",
    "\n",
    "---\n",
    "\n",
    "### 一、矩阵乘法的行向量解释\n",
    "\n",
    "设矩阵 $A \\in \\mathbb{R}^{m \\times p}$，$B \\in \\mathbb{R}^{p \\times n}$，矩阵乘积 $C = AB \\in \\mathbb{R}^{m \\times n}$ 的第 $i$ 行可以表示为：\n",
    "\n",
    "$$\n",
    "C[i, :] = \\sum_{k=1}^p A[i, k] \\cdot B[k, :]\n",
    "$$\n",
    "\n",
    "也就是说，**$C$ 的第 $i$ 行**是由 $B$ 的行向量 $\\{B[1,:], B[2,:], \\dots, B[p,:]\\}$ 加权组合得到的，其中权重是 $A$ 的第 $i$ 行。\n",
    "\n",
    "换句话说，把 $A$ 的第 $i$ 行视为一组线性组合系数，作用在 $B$ 的行上，得到 $C$ 的第 $i$ 行。\n",
    "\n",
    "---\n",
    "\n",
    "### 二、函数 `row_LC` 的数学含义\n",
    "\n",
    "函数 `row_LC(B, coefficients)` 所做的事是：\n",
    "\n",
    "> 给定一个矩阵 $B \\in \\mathbb{R}^{p \\times n}$，和一个系数向量 $\\mathbf{a} \\in \\mathbb{R}^{p}$，计算线性组合：\n",
    "$$\n",
    "\\mathbf{v} = \\sum_{k=1}^p a_k \\cdot \\mathbf{b}_k\n",
    "$$\n",
    "其中 $\\mathbf{b}_k = B[k, :]$ 是 $B$ 的第 $k$ 行。\n",
    "\n",
    "这个过程本质上是将 $B$ 看作由 $p$ 个 $n$ 维行向量组成，对这些行向量进行线性加权。\n",
    "\n",
    "---\n",
    "\n",
    "### 三、函数 `matrix_multiplication_row_LC` 的数学含义\n",
    "\n",
    "该函数的目的是用**行向量线性组合的方式计算矩阵乘积**，即：\n",
    "\n",
    "设 $A \\in \\mathbb{R}^{m \\times p}$，$B \\in \\mathbb{R}^{p \\times n}$，则对每个 $i = 1, \\dots, m$：\n",
    "\n",
    "- 取 $A$ 的第 $i$ 行 $\\mathbf{a}_i = A[i, :]$\n",
    "- 结果 $C$ 的第 $i$ 行是：\n",
    "$$\n",
    "C[i, :] = \\sum_{k=1}^p a_{ik} \\cdot B[k, :]\n",
    "$$\n",
    "\n",
    "从而得到整个矩阵乘积：\n",
    "$$\n",
    "C = AB \\in \\mathbb{R}^{m \\times n}\n",
    "$$\n",
    "\n",
    "这实际上是对矩阵乘法\n",
    "$$\n",
    "C_{ij} = \\sum_{k=1}^p A_{ik} B_{kj}\n",
    "$$\n",
    "的**按行视角重写**。\n",
    "\n",
    "---\n",
    "\n",
    "### 四、具体矩阵示例\n",
    "\n",
    "我们定义：\n",
    "\n",
    "$$\n",
    "A = \\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix} \\in \\mathbb{R}^{2 \\times 3}, \\quad\n",
    "B = A^T = \\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix} \\in \\mathbb{R}^{3 \\times 2}\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 五、计算 $AB$（行组合）\n",
    "\n",
    "通过 `matrix_multiplication_row_LC(A, B)` 得到：\n",
    "$$\n",
    "AB = \\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix}\n",
    "=\n",
    "\\begin{bmatrix}\n",
    "14 & 32 \\\\\n",
    "32 & 77\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "计算细节：\n",
    "\n",
    "- 第1行组合权重为 $[1, 2, 3]$：\n",
    "  $$\n",
    "  1 \\cdot B[0,:] + 2 \\cdot B[1,:] + 3 \\cdot B[2,:] =\n",
    "  1 \\cdot [1, 4] + 2 \\cdot [2, 5] + 3 \\cdot [3, 6] =\n",
    "  [14, 32]\n",
    "  $$\n",
    "\n",
    "- 第2行组合权重为 $[4, 5, 6]$：\n",
    "  $$\n",
    "  4 \\cdot [1, 4] + 5 \\cdot [2, 5] + 6 \\cdot [3, 6] =\n",
    "  [32, 77]\n",
    "  $$\n",
    "\n",
    "这验证了矩阵乘法 $AB$ 可以通过 **行向量组合 $B$ 的行** 得到。\n",
    "\n",
    "---\n",
    "\n",
    "### 六、计算 $BA$（行组合）\n",
    "\n",
    "我们再反过来看 `matrix_multiplication_row_LC(B, A)`，即：\n",
    "\n",
    "$$\n",
    "BA = \\begin{bmatrix}\n",
    "1 & 4 \\\\\n",
    "2 & 5 \\\\\n",
    "3 & 6\n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "1 & 2 & 3 \\\\\n",
    "4 & 5 & 6\n",
    "\\end{bmatrix}\n",
    "=\n",
    "\\begin{bmatrix}\n",
    "17 & 22 & 27 \\\\\n",
    "22 & 29 & 36 \\\\\n",
    "27 & 36 & 45\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "这里每一行结果是将 $A$ 的行向量 $[1, 2, 3], [4, 5, 6]$ 作为**加权对象**，使用 $B$ 的行作为权重。\n",
    "\n",
    "例如，第1行组合是：\n",
    "$$\n",
    "1 \\cdot [1, 2, 3] + 4 \\cdot [4, 5, 6] = [17, 22, 27]\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 七、总结\n",
    "\n",
    "整个过程本质上是通过**行向量线性组合**来理解矩阵乘法：\n",
    "\n",
    "- 每一行结果是组合 $B$ 的行向量得到的；\n",
    "- 线性组合系数是来自矩阵 $A$ 的行；\n",
    "- 和传统矩阵乘法结果一致，但提供了**更强的直观性与结构感知**。\n",
    "\n",
    "公式表达如下：\n",
    "\n",
    "$$\n",
    "(AB)[i, :] = \\sum_{k=1}^p A[i, k] \\cdot B[k, :] \\quad \\forall i = 1, \\dots, m\n",
    "$$\n",
    "\n",
    "这种方式有助于从**行空间**理解线性变换，尤其在深度学习中（如前向传播中的仿射变换）具有良好解释力。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b968d619-8473-4a87-9913-305ea68ada4c",
   "metadata": {},
   "source": [
    "## 初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6a5f9ea-49e3-4085-9f34-d8060a01971f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "198b0f4a-6067-4ea9-9646-ea465a8bbdb0",
   "metadata": {},
   "source": [
    "## 定义行向量线性组合函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "52fe09c7-3c51-4bb6-be12-d80ffbd8a5f9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def row_LC(B, coefficients):\n",
    "\n",
    "    p, n = B.shape\n",
    "    row_LC_result = np.zeros(n)  # 初始化组合结果\n",
    "    \n",
    "    for k in range(p):\n",
    "        row_LC_result += coefficients[k] * B[k,:]  \n",
    "        # 每行乘系数并相加\n",
    "    return row_LC_result"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44ec9320-2b92-4ec2-964b-5a314d33303c",
   "metadata": {},
   "source": [
    "## 定义矩阵乘法函数（行线性组合法）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f54ee3cb-32dd-4e6b-befd-97e7da4c0a52",
   "metadata": {},
   "outputs": [],
   "source": [
    "def matrix_multiplication_row_LC(A, B):\n",
    "    # 获取矩阵 A 和 B 的形状\n",
    "    m, p_A = A.shape\n",
    "    p_B, n = B.shape\n",
    "\n",
    "    # 检测矩阵形状是否符合矩阵乘法规则\n",
    "    if p_A != p_B:\n",
    "        raise ValueError('Dimensions do not match')\n",
    "\n",
    "    # 初始化结果矩阵 C，形状 (m, n)，初始值设为 0\n",
    "    C = np.zeros((m, n))\n",
    "\n",
    "    for i in range(m):\n",
    "        coeffs = A[i, :]             \n",
    "        # 取出 A 的第 i 列，作为线性组合的系数\n",
    "        C[i,:] = row_LC(B, coeffs)  \n",
    "        # 计算 B 行向量的线性组合\n",
    "    \n",
    "    return C"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a0b00d4-4575-41d0-8e39-c76100449c46",
   "metadata": {},
   "source": [
    "## 矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e15d1958-8ad4-4a88-86c7-e17b22a939a6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[1, 2, 3],\n",
    "              [4, 5, 6]])\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6875ee14-a8a7-4816-aa30-ffccad7e4bd9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 4],\n",
       "       [2, 5],\n",
       "       [3, 6]])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B = A.T\n",
    "B"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0daec3c7-fca4-466d-803d-9ced78564f5b",
   "metadata": {},
   "source": [
    "## 矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "d8905379-1f41-4abd-99fc-4aaddf268bf7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[14., 32.],\n",
       "       [32., 77.]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "matrix_multiplication_row_LC(A, B)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5c75a853-f9cd-4588-8893-a840633b2462",
   "metadata": {},
   "outputs": [],
   "source": [
    "A @ B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "5004e8fb-b831-4ea8-b0ad-e0702bccfe3e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[17., 22., 27.],\n",
       "       [22., 29., 36.],\n",
       "       [27., 36., 45.]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "matrix_multiplication_row_LC(B, A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "884a80f4-d1ee-4a26-9df5-e590dd0eb3c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "B @ A"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49d8802e-23d1-4c40-82a0-b0ce8ca8f057",
   "metadata": {},
   "source": [
    "作者\t**生姜DrGinger**  \n",
    "脚本\t**生姜DrGinger**  \n",
    "视频\t**崔崔CuiCui**  \n",
    "开源资源\t[**GitHub**](https://github.com/Visualize-ML)  \n",
    "平台\t[**油管**](https://www.youtube.com/@DrGinger_Jiang)\t\t\n",
    "\t\t[**iris小课堂**](https://space.bilibili.com/3546865719052873)\t\t\n",
    "\t\t[**生姜DrGinger**](https://space.bilibili.com/513194466)  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
